/*
 * Created on 2006-9-8
 *
 * TODO To change the template for this generated file go to
 * Window - Preferences - Java - Code Style - Code Templates
 */
package com.qf.common.dao.hibernate;

import java.io.Serializable;
import java.sql.SQLException;
import java.util.List;

import org.hibernate.Criteria;
import org.hibernate.HibernateException;
import org.hibernate.Query;
import org.hibernate.Session;
import org.hibernate.criterion.Criterion;
import org.hibernate.criterion.Order;
import org.hibernate.criterion.Projections;
import org.springframework.orm.hibernate3.HibernateCallback;
import org.springframework.orm.hibernate3.support.HibernateDaoSupport;

import com.qf.common.dao.PaginationSupport;

/**
 * @author Eve
 * 
 * TODO To change the template for this generated type comment go to Window -
 * Preferences - Java - Code Style - Code Templates
 */
public class HibernateCommonDAO extends HibernateDaoSupport {
	private boolean cacheQueries = false;

	private String queryCacheRegion;

	private Class entityClass = java.io.Serializable.class;

	protected void initDao() throws Exception {
		super.initDao();
		getHibernateTemplate().setCacheQueries(cacheQueries);
		if (queryCacheRegion != null) {
			getHibernateTemplate().setQueryCacheRegion(queryCacheRegion);
		}
	}

	public void setCacheQueries(boolean cacheQueries) {
		this.cacheQueries = cacheQueries;
	}

	public void setQueryCacheRegion(String queryCacheRegion) {
		this.queryCacheRegion = queryCacheRegion;
	}

	public Class getEntityClass() {
		return entityClass;
	}

	public void setEntityClass(Class entityClass) {
		this.entityClass = entityClass;
	}

	// helper methods for create/update/delete
	public Serializable create(final Object entity) {
		return getHibernateTemplate().save(entity);
	}

	public void update(final Object entity) {
		getHibernateTemplate().update(entity);
	}

	public void delete(final Object entity) {
		getHibernateTemplate().delete(entity);
	}

	// helper methods for query
	public Object loadById(final Serializable id) {
		return getHibernateTemplate().get(this.entityClass, id);
	}

	public List findAll() {
		return getHibernateTemplate()
				.find("from " + this.entityClass.getName());
	}

	public List findByNamedQuery(final String namedQuery) {
		return getHibernateTemplate().findByNamedQuery(namedQuery);
	}

	public List findByNamedQuery(final String query, final int firstResult,
			final int maxResults) {
		return findByNamedQuery(query, (Object[]) null, firstResult, maxResults);
	}

	public List findByNamedQuery(final String query, final Object parameter) {
		return getHibernateTemplate().findByNamedQuery(query, parameter);
	}

	public List findByNamedQuery(final String query, final Object parameter,
			final int firstResult, final int maxResults) {

		return findByNamedQuery(query, new Object[] { parameter }, firstResult,
				maxResults);
	}

	public List findByNamedQuery(final String query, final Object[] parameters) {
		return getHibernateTemplate().findByNamedQuery(query, parameters);
	}

	public List findByNamedQuery(final String query, final Object[] parameters,
			final int firstResult, final int maxResults) {

		return (List) getHibernateTemplate().execute(new HibernateCallback() {
			public Object doInHibernate(Session session)
					throws HibernateException, SQLException {

				Query queryObject = session.getNamedQuery(query);
				if (parameters != null) {
					for (int i = 0; i < parameters.length; i++) {
						queryObject.setParameter(i, parameters[i]);
					}
				}
				queryObject.setFirstResult(firstResult);
				queryObject.setMaxResults(maxResults);

				return queryObject.list();

			}
		}, true);

	}

	public List find(final String query) {
		return getHibernateTemplate().find(query);
	}

	public List find(final String queryString, Object[] values) {
		return getHibernateTemplate().find(queryString, values);
	}

	public PaginationSupport find(final Criterion[] criterions, int page,
			int rowPerPage) {
		return find(this.entityClass, criterions, null, page, rowPerPage);
	}

	public PaginationSupport find(final Criterion[] criterions,
			final Order[] orders, int page, int rowPerPage) {
		if (page < 1)
			page = 1;
		return find(this.entityClass, criterions, orders, page, rowPerPage);
	}

	public PaginationSupport find(Query query, int page, int rowPerPage) {
		if (page < 1)
			page = 1;
		return paginationFindByNativeSql(query, page, rowPerPage);
	}

	public List find(final Criterion[] criterions, final Order[] orders) {
		final Class entity = this.entityClass;
		return (List) getHibernateTemplate().execute(new HibernateCallback() {
			public Object doInHibernate(Session session)
					throws HibernateException, SQLException {
				Criteria criteria = session.createCriteria(entity);
				if (criterions != null) {
					for (int i = 0; i < criterions.length; i++) {
						criteria.add((Criterion) criterions[i]);
					}
				}
				if (orders != null) {
					for (int i = 0; i < orders.length; i++) {
						criteria.addOrder(orders[i]);
					}
				}
				criteria.setProjection(null);
				return criteria.list();
			}
		});
	}

	private PaginationSupport find(final Class entity,
			final Criterion[] criterions, final Order[] orders, final int page,
			final int rowPerPage) {
		return (PaginationSupport) getHibernateTemplate().execute(
				new HibernateCallback() {
					public Object doInHibernate(Session session)
							throws HibernateException, SQLException {
						Criteria criteria = session.createCriteria(entity);
						if (criterions != null) {
							for (int i = 0; i < criterions.length; i++) {
								criteria.add((Criterion) criterions[i]);
							}
						}
						PaginationSupport ps = new PaginationSupport(page,
								rowPerPage);
						ps.setTotalCount(((Integer) criteria.setProjection(
								Projections.rowCount()).uniqueResult())
								.intValue());
						if (orders != null) {
							for (int i = 0; i < orders.length; i++) {
								criteria.addOrder(orders[i]);
							}
						}
						criteria.setProjection(null);
						criteria.setFirstResult(ps.getStartIndex())
								.setMaxResults(ps.getCountOnEachPage());

						ps.setItems(criteria.list());
						return ps;
					}
				});
	}

	private PaginationSupport paginationFindByNativeSql(final Query query,
			final int page, final int rowPerPage) {
		return (PaginationSupport) getHibernateTemplate().execute(
				new HibernateCallback() {
					public Object doInHibernate(Session session)
							throws HibernateException, SQLException {
						Query queryObject = query;
						PaginationSupport ps = new PaginationSupport(page,
								rowPerPage);
						ps.setTotalCount(queryObject.list().size());
						queryObject.setFirstResult(ps.getStartIndex());
						queryObject.setMaxResults(ps.getCountOnEachPage());
						ps.setItems(queryObject.list());
						return ps;
					}
				});
	}
}
